package paper.parse;

import java.util.Vector;
import java.util.Iterator;
import java.util.regex.*;

import paper.parse.AuthorList;
import paper.parse.Author;

import paper.db.Paper;

public class AuthorParse {

    final static String initial = "[A-Z](\\.|\\b|\\B|$)";
    final static String name    = "([A-Z][-'a-zA-Z]+)( |\\b|\\B)";
    final static String either  = "([A-Z][-\\.'a-zA-Z]*)";


    final static String revName =
        name + "( " + name + ")*" + ", ?(" + initial + "( ?"+ initial + ")*)";
    final static String revNameTwo = " ?(,|&|,&|;|;&) ?" + revName;
    final static String revList    = revName + "(" + revNameTwo +")*" ; 

    final static Pattern revPatt = Pattern.compile(revList);
    final static Pattern revNamePatt = Pattern.compile(revName);
    final static Pattern revNameTwoPatt = Pattern.compile(revNameTwo);

    
    final static String ordName = "(" + either + "( " + either + ")+)";
    final static String ordNameTwo = " ?(,|&|,&|;|;&) ?" + ordName;
    final static String ordList    = ordName + "(" + ordNameTwo +")*" ; 

    final static Pattern ordPatt = Pattern.compile(ordList);
    final static Pattern ordNamePatt = Pattern.compile(ordName);
    final static Pattern ordNameTwoPatt = Pattern.compile(ordNameTwo);

    AuthorList aList = new AuthorList();

    public AuthorParse() {
    }

    public void parseCitedAuthors(String x) {
        String sane = x
            .replaceAll("\\.","\\. ")
            .replaceAll("\\b(and|AND) ","&")
            .replaceAll("[ \n]+"," ")
            .replaceAll(" *& *","&")
            ;
//        System.out.println("Parsing ... " + sane);
        Matcher m = revPatt.matcher(sane);
        if (m.matches()) {
            if (false) {
                try {
                    for (int i = 0; i <100; i++) {
                        System.out.println("Group " + i + " >" + m.group(i) + "<");
                    }
                } catch (Exception e) {
                    System.out.println("ran out " + e);
                }
            }
            m = revNamePatt.matcher(sane);
            m.find();
            addRevName(0, m.group(1), m.group(6));
            int start = m.end();
            int cnt = 1;
            while (start < sane.length()) {
//                System.out.println("StartRev " + start);
                m = revNameTwoPatt.matcher(sane);
                if (m.find(start)) {
                    addRevName(cnt++, m.group(2), m.group(7));
                    start = m.end();
                } else {
                    System.err.println("INCONSISTENT SHIT " + sane);
                    break;
                }
            }
            return;
        }
        m = ordPatt.matcher(sane);
        if (m.find()) {
            if (false) {
                try {
                    for (int i = 0; i <100; i++) {
                        System.out.println("Group " + i + " >" + m.group(i) + "<");
                    }
                } catch (Exception e) {
                    System.out.println("ran out " + e);
                }
            }
            m = ordNamePatt.matcher(sane);
            m.find();
            addOrdName(0, m.group(1));
            int start = m.end();
            int cnt = 1;
            while (start < sane.length()) {
//                System.out.println("Start " + start);
                m = ordNameTwoPatt.matcher(sane);
                if (m.find(start)) {
                    addOrdName(cnt++, m.group(2));
                    start = m.end();
                } else {
                    System.err.println("INCONSISTENT SHIT ORD " + sane);
                    break;
                }
            }
            return;
        }
        System.out.println("No cigar: " + sane);
    }


    public void parsePaperAuthors(String x) {
        String sane = (x+";")
            .replaceAll("[0-9\\*\\+]","")
            .replaceAll("\\.","\\. ")
            .replaceAll("\\b(and|AND) ",";")
            .replaceAll("[ \n]+"," ")
            .replaceAll(" *(;|,)(;|,| )+ *",";")
            ;
//        System.out.println("Parsing ... " + sane);
        Matcher m;
        int start = 0;
        int cnt = 0;
        while (start < sane.length()) {
//            System.out.println("Start " + start);
            m = ordNamePatt.matcher(sane);
            if (m.find(start)) {
//                System.out.println("Got " + m.start() + " " + m.end() + " >" + m.group() + "<");
                addOrdName(cnt++, m.group(1));
                start = m.end() + 1;
            } else {
                System.err.println("INCONSISTENT SHIT PAPER " + sane);
                break;
            }
        }
    }

    private void addRevName(int sequence, String surname, String initials) {
        initials = initials.replaceAll("[\\. ]","");
        Author a = new Author();
        a.addSurname(surname);
        for (int i = 0; i < initials.length(); i++) {
            a.addGivenName(initials.substring(i,i+1));
        }
        aList.addAuthor(a,sequence,1.0);
    }

    private void addOrdName(int sequence, String name) {
        String[] names = name.split("[\\. ]+");
        for (int j = 1; j < names.length; j++) {
            Author a = new Author();
            for (int i = 0; i < j; i++) {
                a.addGivenName(names[i]);
            }
            for (int i = j; i < names.length; i++) {
                a.addSurname(names[i]);
            }
            aList.addAuthor(a,sequence,names[j].length() > 1? 1.0-j/100:0.125);
        }
    }

    public Vector<String> findBest() {
        Vector<Author> best = aList.findBest();
        if (best != null) {
            Vector<String> result = new Vector<String>();
            for (Iterator<Author> i = best.iterator(); i.hasNext(); ){
                result.add(i.next().toString());
            }
            return result;
        } else {
            return null;
        }
    }

    static public void sortAuthors(String key) {
        Vector <String> auths = Paper.getAuthorsCiting(key);
        AuthorParse ap = new AuthorParse();
        for (Iterator<String> i = auths.iterator(); i.hasNext(); ){
            String a = i.next();
            ap.parseCitedAuthors(a);
        }
        auths = Paper.getAuthorsPDFFile(key);
        for (Iterator<String> i = auths.iterator(); i.hasNext(); ){
            String a = i.next();
            ap.parsePaperAuthors(a);
        }
        Vector <String> saneAuthors = ap.findBest();
        if (saneAuthors != null) {
            Paper.setSaneAuthors(key,saneAuthors);
        }
    }


}
